package com.ybear.ybutils.utils.toast;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;

import com.ybear.ybutils.utils.R;
import com.ybear.ybutils.utils.Utils;

/**
 * 圆角帮助类
 */
class ToastXShapeHelper implements IToastXShape {
    private Context mContext;
    private Paint mPaint;
    private PaintFlagsDrawFilter mDrawFilter;
    private PorterDuffXfermode mXfermodeIn, mXfermodeOut;
    private Canvas mShapeCanvas;
    private RectF mRectF;

    private float mRadius;
    private int mBorderSize;
    @ColorInt
    private int mBorderColor;
    private int mShadowRadius, mShadowOffsetX, mShadowOffsetY;
    @ColorInt
    private int mShadowColor;

    <T extends View> ToastXShapeHelper init(@NonNull T v) {
        mContext = v.getContext();
        mPaint = new Paint();
        //画布抗锯齿
        mDrawFilter = new PaintFlagsDrawFilter(
                0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG
        );
        mRectF = new RectF();
        mShapeCanvas = new Canvas();
        /* 保留上层交集图像 */
        mXfermodeIn = new PorterDuffXfermode( PorterDuff.Mode.DST_IN );
        /* 消除上层图像 */
        mXfermodeOut = new PorterDuffXfermode( PorterDuff.Mode.DST_OUT );
        //启用抗锯齿
        mPaint.setAntiAlias( true );
        //消除画布的抗锯齿
        mShapeCanvas.setDrawFilter( mDrawFilter );
        //启用硬件加速，否则会出现一些异常（比如黑边，设计器和模拟器可能依旧会存在黑边）
        v.setLayerType( View.LAYER_TYPE_HARDWARE, mPaint );
        return this;
    }

    @Override
    public void setRadius(int radius) { mRadius = radius; }

    @Override
    public void setBorderSize(int borderSize) { mBorderSize = borderSize; }
    @Override
    public void setBorderColor(@ColorInt int color) { mBorderColor = color; }

    @Override
    public void setShadowRadius(int radius) { mShadowRadius = radius; }
    @Override
    public void setShadowColor(@ColorInt int color) { mShadowColor = color; }
    @Override
    public void setShadowOffsetX(int offsetX) { mShadowOffsetX = offsetX; }
    @Override
    public void setShadowOffsetY(int offsetY) { mShadowOffsetY = offsetY; }

    public void dispatchDraw(Canvas canvas, View v) {
        int width = v.getWidth();
        int height = v.getHeight();
        if( width <= 0 || height <= 0 ) {
            v.measure( 0, 0 );
            width = v.getMeasuredWidth();
            height = v.getMeasuredHeight();
        }
        if( width <= 0 || height <= 0 ) return;

        //消除画布的抗锯齿
        canvas.setDrawFilter( mDrawFilter );
        //获取绘制圆角部分的图片
        drawShape( canvas, width, height );
        //绘制阴影
        drawShadow( canvas, width, height );
        //绘制描边
        drawStroke( canvas, width, height );
    }

    /**
     * 绘制圆角部分的图片。
     * @param canvas    画布
     * @param width     高度
     * @param height    宽度
     */
    private void drawShape(Canvas canvas, int width, int height) {
        //建立一个空白图片，在里边绘制圆角
        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
        Canvas shapeCanvas = getCanvas();
        //初始化矩形
        initRectF(
                mBorderSize,
                mBorderSize,
                width - mBorderSize,
                height - mBorderSize
        );
        //设置图片
        shapeCanvas.setBitmap( shapeBmp );
        //绘制形状
        drawShape( shapeCanvas, mRectF );
        //绘制时消除绘制的圆角(或者注释掉看效果就明白了)
        mPaint.setXfermode( mXfermodeIn );
        //绘制最终的结果
        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
        mPaint.setXfermode( null );
    }

    /**
     * 绘制描边
     * @param canvas    画布
     */
    private void drawStroke(Canvas canvas, int width, int height) {
        if( mBorderSize == 0 ) return;
        Canvas strokeCanvas = getCanvas();
        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
        //初始化矩形
        initRectF( 0, 0, width, height );
        //描边颜色
        mPaint.setColor( mBorderColor );
        //设置图片
        strokeCanvas.setBitmap( shapeBmp );
        //绘制描边
        drawShape( strokeCanvas, mRectF );

        /* 绘制空心效果 */
        mRectF.left += mBorderSize;
        mRectF.top += mBorderSize;
        mRectF.right -= mBorderSize;
        mRectF.bottom -= mBorderSize;
        mPaint.setXfermode( mXfermodeOut );
        //绘制空心
        drawShape( strokeCanvas, mRectF );
        mPaint.setXfermode( null );
        //提交最终结果
        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
    }

    /**
     * 绘制阴影
     * @param canvas    画布
     */
    private void drawShadow(Canvas canvas, int width, int height) {
        if( mShadowRadius == 0 ) return;
        int color = getShadowColor();
        Canvas shadowCanvas = getCanvas();
        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
        //初始化矩形
        initRectF( 0, 0, width, height );
        //设置图片
        shadowCanvas.setBitmap( shapeBmp );
        //创建阴影
        mPaint.setShadowLayer( mShadowRadius, mShadowOffsetX, mShadowOffsetY, color );
        drawShape( shadowCanvas, mRectF );
        //关闭阴影
        mPaint.setShadowLayer( 0F, 0F, 0F, color );

        float dp = Utils.dp2Px( mContext, 0.1F );
        //初始化矩形
        initRectF( -dp, -dp, width + dp, height + dp );
        /* 绘制空心效果 */
        mPaint.setXfermode( mXfermodeOut );
        //绘制空心
        drawShape( shadowCanvas, mRectF );
        mPaint.setXfermode( null );
        //提交最终结果
        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
    }

    public Canvas getCanvas() {
        mShapeCanvas.drawColor( Color.TRANSPARENT );
        return mShapeCanvas;
    }

    /**
     * 绘制形状
     * @param canvas    画布
     * @param rectF     形状大小
     */
    private void drawShape(Canvas canvas, RectF rectF) {
        if( mRadius > 0 ) {
            canvas.drawRoundRect( rectF, mRadius, mRadius, mPaint );
            return;
        }
        canvas.drawRect( rectF, mPaint );
    }

    private void initRectF(float left, float top, float right, float bottom) {
        mRectF.set(
                left + mShadowRadius * 2,
                top + mShadowRadius * 2,
                right - mShadowRadius * 2,
                bottom - mShadowRadius * 2
        );
    }

    private int getShadowColor() {
        if( mContext == null ) return Color.BLACK;
        return mShadowColor != 0 ?
                mShadowColor :
                mContext.getResources().getColor( R.color.colorShadow );
    }
}
